package com.watch.system.service.impl;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTPayload;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.watch.system.common.constant.CacheConstants;
import com.watch.system.common.enums.CaptchaTypeEnum;
import com.watch.system.common.util.DateUtils;
import com.watch.system.converter.CarAdConverter;
import com.watch.system.converter.CarAuthConverter;
import com.watch.system.mapper.CarAuthMapper;
import com.watch.system.model.bo.UserFormBO;
import com.watch.system.model.dto.CaptchaResult;
import com.watch.system.model.dto.LoginResult;
import com.watch.system.model.entity.CarAuth;
import com.watch.system.model.entity.CarUser;
import com.watch.system.model.form.AuthForm;
import com.watch.system.model.form.MsgDescForm;
import com.watch.system.model.form.UserForm;
import com.watch.system.model.query.CarAuthPageQuery;
import com.watch.system.model.vo.CarAuthExportVO;
import com.watch.system.model.vo.CarAuthImportVO;
import com.watch.system.model.vo.CarAuthPageVO;
import com.watch.system.model.vo.CarUserPageVO;
import com.watch.system.plugin.captcha.CaptchaProperties;
import com.watch.system.service.AuthService;
import com.watch.system.security.util.JwtUtils;
import com.watch.system.service.CarUserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.awt.*;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 认证服务实现类
 *
 * @author haoxr
 * @since 2.4.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AuthServiceImpl extends ServiceImpl<CarAuthMapper, CarAuth> implements AuthService {

    private final AuthenticationManager authenticationManager;
    private final StringRedisTemplate redisTemplate;
    private final CodeGenerator codeGenerator;
    private final Font captchaFont;
    private final CaptchaProperties captchaProperties;

    private final CarAuthConverter carAuthConverter;

    private final CarUserService carUserService;
    /**
     * 登录
     *
     * @param username 用户名
     * @param password 密码
     * @return 登录结果
     */
    @Override
    public LoginResult login(String username, String password) {
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(username.toLowerCase().trim(), password);
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        String accessToken = JwtUtils.generateToken(authentication);
        return LoginResult.builder()
                .tokenType("Bearer")
                .accessToken(accessToken)
                .build();
    }

    /**
     * 注销
     */
    @Override
    public void logout() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (StrUtil.isNotBlank(token)) {

            Map<String, Object> claims = JwtUtils.parseToken(token);
            String jti = Convert.toStr(claims.get(JWTPayload.JWT_ID));
            Long expiration = Convert.toLong(claims.get(JWTPayload.EXPIRES_AT));
            if (expiration != null) {
                long ttl = expiration - System.currentTimeMillis() / 1000;
                redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null, ttl, TimeUnit.SECONDS);
            } else {
                redisTemplate.opsForValue().set(CacheConstants.BLACKLIST_TOKEN_PREFIX + jti, null);
            }
        }
        SecurityContextHolder.clearContext();
    }

    /**
     * 获取验证码
     *
     * @return 验证码
     */
    @Override
    public CaptchaResult getCaptcha() {

        String captchaType = captchaProperties.getType();
        int width = captchaProperties.getWidth();
        int height = captchaProperties.getHeight();
        int interfereCount = captchaProperties.getInterfereCount();
        int codeLength = captchaProperties.getCode().getLength();

        AbstractCaptcha captcha;
        if (CaptchaTypeEnum.CIRCLE.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createCircleCaptcha(width, height, codeLength, interfereCount);
        } else if (CaptchaTypeEnum.GIF.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createGifCaptcha(width, height, codeLength);
        } else if (CaptchaTypeEnum.LINE.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createLineCaptcha(width, height, codeLength, interfereCount);
        } else if (CaptchaTypeEnum.SHEAR.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createShearCaptcha(width, height, codeLength, interfereCount);
        } else {
            throw new IllegalArgumentException("Invalid captcha type: " + captchaType);
        }
        captcha.setGenerator(codeGenerator);
        captcha.setTextAlpha(captchaProperties.getTextAlpha());
        captcha.setFont(captchaFont);

        String captchaCode = captcha.getCode();
        String imageBase64Data = captcha.getImageBase64Data();

        // 验证码文本缓存至Redis，用于登录校验
        String captchaKey = IdUtil.fastSimpleUUID();
        redisTemplate.opsForValue().set(CacheConstants.CAPTCHA_CODE_PREFIX + captchaKey, captchaCode,
                captchaProperties.getExpireSeconds(), TimeUnit.SECONDS);

        return CaptchaResult.builder()
                .captchaKey(captchaKey)
                .captchaBase64(imageBase64Data)
                .build();
    }

    @Override
    public IPage<CarAuthPageVO> getAuthPage(CarAuthPageQuery queryParams) {
        // 参数构建
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        Page<CarAuthPageVO> page = new Page<>(pageNum, pageSize);
        // 格式化为数据库日期格式，避免日期比较使用格式化函数导致索引失效
        if(StringUtils.isNotEmpty(queryParams.getStartTime()) && StringUtils.isNotEmpty(queryParams.getEndTime())) {
            DateUtils.toDatabaseFormat(queryParams, "startTime", "endTime");
        }
        // 查询数据
        Page<CarAuthPageVO> authPage = this.baseMapper.getAuthPage(page, queryParams);
        // 实体转换
        return authPage;
    }


    @Override
    public boolean updateAuth(Integer authId, AuthForm authForm) {

        CarAuth entity = carAuthConverter.form2Entity(authForm);
        // 修改认证
        int result = this.baseMapper.updateCarAuth(entity);

        if("1".equals(entity.getStatus())){
            MsgDescForm msgDescForm=new MsgDescForm();
            msgDescForm.setUserId(entity.getUserId());
            msgDescForm.setMsgDesc("您提交的车主认证已通过审核，快去开启你的车有圈之旅吧！");
            msgDescForm.setType("3");
            msgDescForm.setCreateDate(new Date());
            this.baseMapper.insertMsg(msgDescForm);
            //查询用户信息
            CarUser carUser = carUserService.getCarUser(entity.getUserId());
            if(carUser!=null && "0".equals(carUser.getStatus())){
                boolean isModResult = carUserService.updateStatus(carUser.getUserId());
                log.info("修改用户状态:{}",isModResult);
            }

        }else{
            MsgDescForm msgDescForm=new MsgDescForm();
            msgDescForm.setUserId(entity.getUserId());
            msgDescForm.setMsgDesc("您提交的车主认证未通过，请修改后重新提交申请！");
            msgDescForm.setType("4");
            msgDescForm.setCreateDate(new Date());
            this.baseMapper.insertMsg(msgDescForm);
        }
        return result>0;
    }


    /**
     * 删除认证
     *
     * @param idsStr 模板ID，多个以英文逗号(,)分割
     * @return
     */
    @Override
    public boolean deleteAuth(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的认证数据为空");
        // 逻辑删除
        List<Long> ids = Arrays.stream(idsStr.split(","))
                .map(Long::parseLong)
                .collect(Collectors.toList());
        return  this.baseMapper.removeByIds(ids);

    }

    @Override
    public List<CarAuthExportVO> listExportAuths(CarAuthPageQuery queryParams) {
        return this.baseMapper.listExportAuths(queryParams);
    }

    @Override
    public boolean saveAuthImport(CarAuthImportVO carAdImportVO) {
        int result=this.baseMapper.saveAuthImport(carAdImportVO);
        return result>0;
    }

}
